home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
BCI NET
/
BCI NET Dec 94.iso
/
archives
/
programming
/
c
/
cc.lha
/
cc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-12
|
20KB
|
993 lines
/**
*** cc.c Unix compatible frontend for Amiga's C compilers
***
*** This program is free software; you can redistribute it and/or modify
*** it under the terms of the GNU General Public License as published by
*** the Free Software Foundation; either version 2 of the License, or
*** (at your option) any later version.
***
*** This program is distributed in the hope that it will be useful,
*** but WITHOUT ANY WARRANTY; without even the implied warranty of
*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*** GNU General Public License for more details.
***
*** You should have received a copy of the GNU General Public License
*** along with this program; if not, write to the Free Software
*** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
***
***
*** Compiler: dcc V3.01
***
*** Computer: Amiga 1200
***
*** Author: Jochen Wiedmann
*** Am Eisteich 9
*** 72555 Metzingen
*** Germany
***
*** Phone: (49)7123 / 14881
*** Internet: wiedmann@zdv.uni-tuebingen.de
***
***
***
*** This is a Unix compatible frontend for gcc, SAS/C and Dice. In fact,
*** it does nothing than else than calling the appropriate frontends
*** with the appropriate options.
***
*** Supported options are:
***
*** -v Verbose (try it :-)
*** -c Don't link
*** -a Compile only, don't assemble
*** -E Run preprocessor only
*** -I<dir> Look for include files in directory <dir>
*** -L<dir> Look for libraries in directory <dir>
*** -o<file> Set the name of the created file; it is recommended
*** to use this as the respective frontends might behave
*** different in selecting default names.
*** -D<symbol> Defines preprocessor symbol; use -Dsymbol=var for
*** specific values.
*** -U<symbol> Undefine the preprocessor symbol <symbol>.
*** -l<lib> Link with library <lib>.
*** -g Turn debugging on.
*** -O Optimize
***
**/
/**
*** Version string
**/
#define VERSION 1
#define REVISION 1
#define DATE "11.10.94"
#define VERS "cc 1.1"
#define VSTRING "cc 1.1 (11.10.94)"
#define VERSTAG "\0$VER: cc 1.1 (11.10.94)"
char Version[] = VSTRING;
char AmigaVersion[] = VERSTAG;
/**
*** Include files
**/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <exec/lists.h>
#include <exec/nodes.h>
#include <clib/alib_protos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <pragmas/exec_pragmas.h>
#include <pragmas/dos_pragmas.h>
extern struct Library *SysBase;
extern struct Library *DOSBase;
/**
*** List of options processed by cc:
**/
typedef enum
{
OPTION_UNKNOWN,
OPTION_VERBOSE,
OPTION_DEFINE,
OPTION_UNDEFINE,
OPTION_PREPROCESSOR_ONLY,
OPTION_ASSEMBLER_ONLY,
OPTION_NOLINK,
OPTION_INCLUDEDIR,
OPTION_LINKDIR,
OPTION_OPTIMIZE,
OPTION_DEBUGGING,
OPTION_LIBRARY,
OPTION_OUTPUT
} CompilerOption;
/**
*** This structure defines an element in the list of options.
**/
typedef struct
{
struct MinNode mn;
CompilerOption Option;
char *Arg;
} CurrentOption;
/**
*** Compatibility mode (Default: gcc)
**/
enum
{
COMPATIBILITYMODE_GCC,
COMPATIBILITYMODE_SAS,
COMPATIBILITYMODE_DICE,
} CompatibilityMode = COMPATIBILITYMODE_GCC;
char *CompatibilityModeNames[] =
{
"-gcc",
"-sas",
"-dice"
};
/**
*** Compiler mode (Default: Everything)
**/
enum
{
COMPILERMODE_PREPROCESSOR_ONLY,
COMPILERMODE_COMPILER_ONLY,
COMPILERMODE_ASSEMBLER_ONLY,
COMPILERMODE_EVERYTHING,
} CompilerMode = COMPILERMODE_EVERYTHING;
char *CompilerModeNames[] =
{
"-E",
"-a",
"-c"
};
/**
*** These lists are used to hold the current options.
**/
struct List OptionList;
/**
*** Guess, what this function does? :-)
**/
void Usage(void)
{
printf("%s%s%s", "Usage: cc [options] [files]\n\
\n\
Options known to cc are:\n\
\n\
-v\t\tbe verbose\n\
-o<file>\t\tsend output to <file> (usage is recommended)\n\
-E\t\trun preprocessor only\n\
-a\t\trun preprocessor and compiler only\n\
-c\t\trun preprocessor, compiler and assembler, don't link\n\
-I<dir>\t\tlook for include files in <dir>\n\
-L<dir>\t\took for link libraries in <dir>\n\
-l<lib>\t\tlink with library <lib>\n\
-g\t\tturn debugging on\n\
-O\t\tturn optimization on\n\
-D<sym>\t\tdefine preprocessor symbol\n\
-U<sym>\t\tundefine preprocessor symbol\n\
-h,--help,?\tprint this message\n\
\n\n", Version, "\n\
©1994 by Jochen Wiedmann, all rights reserved\n\n\
This program is governed by the terms and conditions of the GNU General\n\
Public License. A copy should have come with this distribution. (See the\n\
file COPYING.) In that license it is made clear that you are welcome to\n\
redistribute either verbatim or modified copies of the program and the\n\
documentation under certain conditions. Further you are told that this\n\
program comes with ABSOLUTELY NO WARRANTY!\n\n\n");
exit(5);
}
/**
*** This functions adds a new option to the list of options.
**/
void AddOption(CompilerOption co, char *arg)
{
CurrentOption *cu;
if (!(cu = malloc(sizeof(*cu))))
{
fprintf(stderr, "Out of memory!");
exit(20);
}
cu->Option = co;
cu->Arg = arg;
AddTail(&OptionList, (struct Node *) cu);
}
/**
*** This function handles options which may be splitted into two
*** arguments or not, like -I <dir> or -I<dir>.
**/
void AddOptionArg(CompilerOption co,
int *i,
int argc,
char *argv[])
{
char *arg = &argv[*i][2];
if (!*arg)
{
if (++(*i) >= argc)
{
fprintf(stderr, "%s: Missing argument: %s\n", argv[--(*i)]);
exit(20);
}
arg = argv[*i];
}
AddOption(co, arg);
}
/**
*** This function is used to set the compatibility mode.
**/
void SetCompatibilityMode(int mode, int *set)
{
if (*set)
{
fprintf(stderr, "cc, warning: %s overwrites %s\n",
CompatibilityModeNames[mode],
CompatibilityModeNames[CompatibilityMode]);
exit(10);
}
*set = TRUE;
CompatibilityMode = mode;
}
/**
*** This function is used to set the compatibility mode.
**/
void SetCompilerMode(int mode, int *set)
{
if (*set)
{
fprintf(stderr, "cc warning: %s overwrites %s\n",
CompilerModeNames[mode],
CompilerModeNames[CompilerMode]);
exit(10);
}
*set = TRUE;
CompilerMode = mode;
}
/**
*** This function is used to build the string that is used to call
*** the real frontend. It supports strings of any length, thus it
*** may look somewhat complicated.
**/
void AddToString(char **strptr, char *format, ...)
{
static char buffer[1024]; /* Maximal length of *one* argument */
static int RealLen;
static int MaxLen;
int len;
va_list args;
va_start(args, format);
vsprintf(buffer, format, args);
len = strlen(buffer);
if (!*strptr)
{
MaxLen = 0;
}
if (len + RealLen + 1 > MaxLen)
{
/**
*** Current buffer not sufficient, allocate a new buffer
**/
char *newstr;
if (!(newstr = malloc(MaxLen+1024)))
{
fprintf(stderr, "Out of memory!");
exit(20);
}
MaxLen += 1024;
if (*strptr)
{
strcpy(newstr, *strptr);
}
else
{
*newstr = '\0';
RealLen = 0;
}
*strptr = newstr;
}
strcpy(*strptr + RealLen, buffer);
RealLen += len;
}
/**
*** This function is used to parse the arguments. Options will
*** be included into OptionList, files in FileList.
**/
void ParseArgs(int argc,
char *argv[])
{
int i;
/**
*** These variables are used for checking if arguments repeat.
*** Note that we keep them local: This allows, for example,
*** to use different settings in the environment and on the
*** command line.
**/
int CompatibilityModeIsSet = FALSE;
int CompilerModeIsSet = FALSE;
for (i = 0; i < argc; i++)
{
char *argvi = argv[i];
if (argvi[0] == '-')
{
/**
*** Assume this to be a compiler option.
**/
switch(argvi[1])
{
case '-':
if (strcmp(argvi, "--help") == 0)
{
Usage();
}
AddOption(OPTION_UNKNOWN, argvi);
break;
case 'D':
AddOptionArg(OPTION_DEFINE, &i, argc, argv);
break;
case 'E':
switch(argvi[2])
{
case '\0':
SetCompilerMode(COMPILERMODE_PREPROCESSOR_ONLY,
&CompilerModeIsSet);
break;
default:
AddOption(OPTION_UNKNOWN, argvi);
break;
}
break;
case 'I':
AddOptionArg(OPTION_INCLUDEDIR, &i, argc, argv);
break;
case 'L':
AddOptionArg(OPTION_LINKDIR, &i, argc, argv);
break;
case 'O':
AddOption(OPTION_OPTIMIZE, &argvi[2]);
break;
case 'U':
AddOptionArg(OPTION_UNDEFINE, &i, argc, argv);
break;
case 'a':
switch(argvi[2])
{
case '\0':
SetCompilerMode(COMPILERMODE_COMPILER_ONLY,
&CompilerModeIsSet);
break;
default:
AddOption(OPTION_UNKNOWN, argvi);
break;
}
break;
case 'c':
switch(argvi[2])
{
case '\0':
SetCompilerMode(COMPILERMODE_ASSEMBLER_ONLY,
&CompilerModeIsSet);
break;
default:
AddOption(OPTION_UNKNOWN, argvi);
break;
}
break;
case 'd':
if (strcmp(argvi,
CompatibilityModeNames[COMPATIBILITYMODE_DICE]) == 0)
{
SetCompatibilityMode(COMPATIBILITYMODE_DICE,
&CompatibilityModeIsSet);
}
else
{
AddOption(OPTION_UNKNOWN, argvi);
}
break;
case 'g':
switch(argvi[2])
{
case '\0':
AddOption(OPTION_DEBUGGING, argvi);
break;
default:
if (strcmp(argvi,
CompatibilityModeNames[COMPATIBILITYMODE_GCC]) == 0)
{
SetCompatibilityMode(COMPATIBILITYMODE_GCC,
&CompatibilityModeIsSet);
}
else
{
AddOption(OPTION_UNKNOWN, argvi);
}
break;
}
break;
case 'h':
switch(argvi[2])
{
case '\0':
Usage();
default:
AddOption(OPTION_UNKNOWN, argvi);
break;
}
break;
case 'l':
AddOptionArg(OPTION_LIBRARY, &i, argc, argv);
break;
case 'o':
AddOptionArg(OPTION_OUTPUT, &i, argc, argv);
break;
case 's':
if (strcmp(argvi,
CompatibilityModeNames[COMPATIBILITYMODE_SAS]) == 0)
{
SetCompatibilityMode(COMPATIBILITYMODE_SAS,
&CompatibilityModeIsSet);
}
else
{
AddOption(OPTION_UNKNOWN, argvi);
}
break;
case 'v':
switch(argvi[2])
{
case '\0':
AddOption(OPTION_VERBOSE, argvi);
break;
default:
AddOption(OPTION_UNKNOWN, argvi);
break;
}
break;
default:
AddOption(OPTION_UNKNOWN, argvi);
break;
}
}
else if (strcmp(argvi, "?") == 0)
{
Usage();
}
else
{
AddOption(OPTION_UNKNOWN, argvi);
}
}
}
/**
*** This function calls gcc as a frontend.
**/
int CompileGcc(void)
{
CurrentOption *co;
char *CompileString = NULL;
int Verbose = FALSE;
AddToString(&CompileString, "gcc");
for (co = (CurrentOption *) OptionList.lh_Head;
co->mn.mln_Succ != NULL;
co = (CurrentOption *) co->mn.mln_Succ)
{
switch (co->Option)
{
case OPTION_UNKNOWN:
AddToString(&CompileString, " \"%s\"", co->Arg);
break;
case OPTION_VERBOSE:
AddToString(&CompileString, " -v");
Verbose = TRUE;
break;
case OPTION_DEFINE:
AddToString(&CompileString, " \"-D%s\"", co->Arg);
break;
case OPTION_UNDEFINE:
AddToString(&CompileString, " \"-U%s\"", co->Arg);
break;
case OPTION_PREPROCESSOR_ONLY:
AddToString(&CompileString, " -E");
break;
case OPTION_ASSEMBLER_ONLY:
AddToString(&CompileString, " -a");
break;
case OPTION_NOLINK:
AddToString(&CompileString, " -c");
break;
case OPTION_INCLUDEDIR:
AddToString(&CompileString, " \"-I%s\"", co->Arg);
break;
case OPTION_LINKDIR:
AddToString(&CompileString, " \"-L%s\"", co->Arg);
break;
case OPTION_OPTIMIZE:
AddToString(&CompileString, " \"-O%s\"", co->Arg);
break;
case OPTION_DEBUGGING:
AddToString(&CompileString, " -g");
break;
case OPTION_LIBRARY:
AddToString(&CompileString, " \"-l%s\"", co->Arg);
break;
case OPTION_OUTPUT:
AddToString(&CompileString, " -o \"%s\"", co->Arg);
break;
}
}
AddToString(&CompileString, "\n");
if (Verbose)
{
printf("%s\n%s", Version, CompileString);
}
return(system(CompileString));
}
/**
*** This function calls SAS/C as a frontend.
**/
int CompileSAS(void)
{
CurrentOption *co;
char *CompileString = NULL;
int Verbose = FALSE;
char *OptionOutput = NULL;
AddToString(&CompileString, "sc");
for (co = (CurrentOption *) OptionList.lh_Head;
co->mn.mln_Succ != NULL;
co = (CurrentOption *) co->mn.mln_Succ)
{
switch (co->Option)
{
case OPTION_UNKNOWN:
AddToString(&CompileString, " \"%s\"", co->Arg);
break;
case OPTION_VERBOSE:
AddToString(&CompileString, " VERBOSE");
Verbose = TRUE;
break;
case OPTION_DEFINE:
AddToString(&CompileString, " DEF \"%s\"", co->Arg);
break;
case OPTION_UNDEFINE: /* Not supported */
break;
case OPTION_INCLUDEDIR:
AddToString(&CompileString, " IDIR\"%s\"", co->Arg);
break;
case OPTION_LINKDIR: /* Not supported */
break;
case OPTION_OPTIMIZE:
AddToString(&CompileString, " OPTIMIZE");
break;
case OPTION_DEBUGGING:
AddToString(&CompileString, " DEBUG FULLFLUSH");
break;
case OPTION_LIBRARY:
AddToString(&CompileString, " LIBRARY \"%s.lib\"", co->Arg);
break;
case OPTION_OUTPUT:
OptionOutput = co->Arg;
break;
}
}
switch(CompilerMode)
{
case COMPILERMODE_PREPROCESSOR_ONLY:
AddToString(&CompileString, " PPONLY");
case COMPILERMODE_ASSEMBLER_ONLY:
if (OptionOutput)
{
AddToString(&CompileString, " OBJNAME \"%s\"", OptionOutput);
}
break;
case COMPILERMODE_COMPILER_ONLY:
if (!OptionOutput)
{
OptionOutput = "*";
}
AddToString(&CompileString, " \"DISASM=%s\"", OptionOutput);
break;
case COMPILERMODE_EVERYTHING:
if (OptionOutput)
{
AddToString(&CompileString, " PNAME \"%s\"", OptionOutput);
}
AddToString(&CompileString, " LINK");
break;
}
AddToString(&CompileString, "\n");
if (Verbose)
{
printf("%s\n%s", Version, CompileString);
}
return(system(CompileString));
}
/**
*** This function calls Dice as a frontend.
**/
int CompileDice(void)
{
CurrentOption *co;
char *CompileString = NULL;
int Verbose = FALSE;
switch(CompilerMode)
{
case COMPILERMODE_PREPROCESSOR_ONLY:
AddToString(&CompileString, "dcpp");
break;
case COMPILERMODE_COMPILER_ONLY:
AddToString(&CompileString, "dcc -a");
break;
case COMPILERMODE_ASSEMBLER_ONLY:
AddToString(&CompileString, "dcc -c");
break;
default:
AddToString(&CompileString, "dcc");
break;
}
for (co = (CurrentOption *) OptionList.lh_Head;
co->mn.mln_Succ != NULL;
co = (CurrentOption *) co->mn.mln_Succ)
{
switch (co->Option)
{
case OPTION_UNKNOWN:
AddToString(&CompileString, " \"%s\"", co->Arg);
break;
case OPTION_VERBOSE:
if (CompilerMode != COMPILERMODE_PREPROCESSOR_ONLY)
{
AddToString(&CompileString, " -v", co->Arg);
}
Verbose = TRUE;
break;
case OPTION_DEFINE:
AddToString(&CompileString, " \"-D%s\"", co->Arg);
break;
case OPTION_UNDEFINE: /* Not supported */
break;
case OPTION_INCLUDEDIR:
AddToString(&CompileString, " \"-I%s\"", co->Arg);
break;
case OPTION_LINKDIR:
if (CompilerMode != COMPILERMODE_PREPROCESSOR_ONLY)
{
AddToString(&CompileString, " \"-L%s\"", co->Arg);
}
break;
case OPTION_OPTIMIZE: /* Not suported */
break;
case OPTION_DEBUGGING:
if (CompilerMode != COMPILERMODE_PREPROCESSOR_ONLY)
{
AddToString(&CompileString, " -s -d1");
}
break;
case OPTION_LIBRARY:
if (CompilerMode != COMPILERMODE_PREPROCESSOR_ONLY)
{
AddToString(&CompileString, " \"-l%s\"", co->Arg);
}
break;
case OPTION_OUTPUT:
AddToString(&CompileString, " -o \"%s\"", co->Arg);
break;
}
}
AddToString(&CompileString, "\n");
if (Verbose)
{
printf("%s\n%s", Version, CompileString);
}
return(system(CompileString));
}
/**
*** This function is used to split a string into arguments.
*** It returns an array similar to argv.
***
*** I don't like doing things for myself, but as far as I
*** can see neither SAS nor Dice offer a possibility of
*** doing this.
***
*** Inputs: argstr - the string to split into arguments,
*** for example an AmigaDOS command line;
*** may contain arguments like
*** "This is one argument"
*** or
*** "Note the "" inside this argument"
*** where the double quotation mark will be
*** changed into one.
*** argc - pointer to an int where to store the
*** number of arguments found in argstr
***
*** Result: an NULL terminated array of pointers to the
*** arguments or NULL; note that the pointers go
*** into argstr and argstr will be modified.
**/
char **SplitArgs(char *argstr, int *argcptr)
{
int argc;
char *argptr;
char **argv;
char **argvptr;
/**
*** Parse the string for the first time counting
*** the number of arguments.
**/
argptr = argstr;
argc = 0;
for(;;)
{
/**
*** Skip blanks
**/
while (*argptr == ' ' || *argptr == '\t')
{
++argptr;
}
if (*argptr == '\0' || *argptr == '\n' || *argptr == '\r')
{
break;
}
++argc;
if (*argptr == '\"')
{
do
{
++argptr;
if (*argptr == '\"')
{
if (*(argptr+1) == '\"')
{
++argptr;
}
else
{
break;
}
}
}
while (*argptr != '\0' && *argptr != '\r' && *argptr != '\n');
}
else
{
while (*argptr != '\0' && *argptr != '\r' && *argptr != '\n' &&
*argptr != '\t' && *argptr != ' ')
{
++argptr;
}
}
{
char c;
c = *argptr;
*(argptr++) = '\0';
if (c == '\0' || c == '\r' || c == '\n')
{
break;
}
}
}
*argcptr = argc;
if (!(argv = malloc(sizeof(char *) * (argc+1))))
{
return(NULL);
}
/**
*** Parse the string a second time
**/
for (argvptr = argv, argptr = argstr; argc > 0; --argc, ++argvptr)
{
int inside;
while (*argptr == ' ' || *argptr == '\t')
{
++argptr;
}
if (*argptr == '\"')
{
++argptr;
inside = TRUE;
}
else
{
inside = FALSE;
}
*argvptr = argptr;
while (*argptr)
{
if (*argptr == '\"' && inside)
{
char *ptr;
char *oldptr;
/**
*** Found a "", remove the second ".
**/
for(ptr = argptr++, oldptr = *argvptr;
ptr >= oldptr; --ptr)
{
*(ptr+1) = *ptr;
}
*argvptr = oldptr+1;
}
++argptr;
}
++argptr;
}
*argvptr = NULL;
return(argv);
}
/**
*** Finally main().
**/
int main(int argc, char *argv[])
{
char *cflags;
NewList(&OptionList);
if ((cflags = getenv("CCOPT")))
{
int envargc;
char **envargv;
if (!(envargv = SplitArgs(cflags, &envargc)))
{
fprintf(stderr, "Out of memory!\n");
exit(20);
}
ParseArgs(envargc, envargv);
}
ParseArgs(argc-1, argv+1);
switch(CompatibilityMode)
{
case COMPATIBILITYMODE_GCC:
CompileGcc();
break;
case COMPATIBILITYMODE_SAS:
CompileSAS();
break;
case COMPATIBILITYMODE_DICE:
CompileDice();
break;
}
}